<template>
<div class="move-select">
    <h1>滑动选择,最终返回坐标</h1>
    <div>
      <h1>设置宽高的数量</h1>
      <p>
        宽：<input v-model="originalData.xRows" type="text">
      </p>
      <p>
        高：<input v-model="originalData.yRows" type="text">
      </p>
      <p>
        <button @click="setOriginalData">确定</button>
      </p>
    </div>
    <p>
      开始坐标：x: {{ rectData.startCell.x }} , y: {{ rectData.startCell.y }}
    </p>
    <p>
      结束坐标：x: {{ rectData.endCell.x }} , y: {{ rectData.endCell.y }}
    </p>
    <div class="tables" @mouseleave="showFinalRect">
        <template v-for="(yColumn, index) in tableCells">
            <div class="table-row"
                 :class="{'contain-locked-cell': containLockedCell }"
                 :key="index">
                <template v-for="cell in yColumn.row">
                    <span
                        class="cell"
                        :class="{'is-selected': cell.isSelected,
                        'is-selecting': cell.isSelecting, 'is-locked': cell.isLocked }"
                        :key="`x-${cell.x}-${cell.y}`"
                        :ref="`cell-${cell.y}-${cell.x}`"
                        @click="selectOne(cell)"
                        @mouseenter="showRect(cell)"
                    >{{ cell.x }}</span>
                </template>
            </div>
        </template>
    </div>
</div>
</template>

<script>
export default {
  name: 'MoveSelect',
  data() {
    return {
      originalData: {
        xRows: 20,
        yRows: 20,
      },
      rectData: {
        startCell: {
          x: null,
          y: null,
        },
        endCell: {
          x: null,
          y: null,
        },
      },
      selectCells: [],
      lockedCells: [],
      preSelectedCells: [],
      tableCells: [],
      containLockedCell: false, // 是否包含被锁定的元素
    }
  },
  created() {
    this.generateTable()
  },
  methods: {
    setOriginalData() {
      this.generateTable()
    },
    generateTable() {
      this.tableCells = []
      const { xRows, yRows } = this.originalData
      for (let rowNum = 1; rowNum <= yRows; rowNum += 1) {
        const row = []
        for (let x = 1; x <= xRows; x += 1) {
          const cell = {
            x,
            y: rowNum,
            isSelected: false, // 是否选中了
            isLocked: (x === Math.floor(xRows / 2) && rowNum === Math.floor(xRows / 2))
              || (x === Math.floor(xRows / 3) && rowNum === Math.floor(xRows / 5)), // 是否不能选
            isSelecting: false, // 是否正好在鼠标移动过程中，需要渲染的那个范围
          }
          row.push(cell)
          if (cell.isLocked) {
            this.lockedCells.push(cell)
          }
        }
        this.tableCells.push({
          row,
          rowNum, // 行数
        })
      }
    },
    cancleStyle(cell) {
      cell.isSelected = false
    },
    selectStyle() {
      this.selectCells.forEach((cell) => {
        cell.isSelected = true
      })
    },
    selectOne(cell) {
      // 已经被选中了
      if (cell.isSelected || cell.isLocked || this.containLockedCell) return
      cell.isSelected = true
      if (this.selectCells.length === 2) {
        this.cancleStyle(this.selectCells[0])
        this.selectCells.shift(0)
      }
      this.selectCells.push(cell)
    },
    showRect(currentCell) {
      if (currentCell) {
        if (!this.selectCells.length) return
        const startCell = this.selectCells.length === 2
          ? this.selectCells[1] : this.selectCells[0]
        this.drawRect({ startCell, currentCell })
      } else {
        this.drawRect({ startCell: this.selectCells[0], currentCell: this.selectCells[1] })
      }
    },
    drawRect({ startCell, currentCell }) {
      this.rectData = {
        startCell,
        endCell: currentCell,
      }
      // 先找到四个角再说
      const xRows = startCell.x > currentCell.x
        ? {
          startX: currentCell.x,
          endX: startCell.x,
        } : {
          startX: startCell.x,
          endX: currentCell.x,
        }
      const yRows = startCell.y > currentCell.y
        ? {
          startY: currentCell.y,
          endY: startCell.y,
        } : {
          startY: startCell.y,
          endY: currentCell.y,
        }
      this.tableCells.forEach((currentRow) => {
        if (currentRow.rowNum >= yRows.startY && currentRow.rowNum <= yRows.endY) {
          // 行数 满足条件
          currentRow.row.forEach((cell) => {
            if (cell.x >= xRows.startX && cell.x <= xRows.endX) {
              cell.isSelecting = true
            } else {
              cell.isSelecting = false
            }
          })
        } else { // 不在范围，直接取消
          currentRow.row.forEach((cell) => {
            cell.isSelecting = false
          })
        }
      })

      // 是否包含在内
      // eslint-disable-next-line array-callback-return,consistent-return
      const containLockedCell = this.lockedCells.some((cell) => {
        if (
          cell.x <= xRows.endX
          && cell.x >= xRows.startX
          && cell.y <= yRows.endY
          && cell.y >= yRows.startY) {
          return true
        }
      })
      this.containLockedCell = containLockedCell
    },
    showFinalRect() {
      this.containLockedCell = false
      if (this.selectCells.length === 2) {
        this.showRect()
      }
    },
  },

}
</script>

<style lang="scss" scoped>
.move-select{
    margin: 20px auto;
    width: 1000px;
    height: 90vh;
    text-align: center;
}
.tables{
    display: inline-block;
    background-color: #eee;
    .table-row{
        box-sizing: border-box;
        height: 20px;
        margin: 2px 0;
    }
    .cell{
        display: inline-block;
        width: 20px;
        height: 20px;
        background-color: #fff;
        margin: 0 1px;
        cursor: pointer;
        &:not(.is-selected):hover{
            background-color: green;
            color: #fff;
        }
    }
  .is-selected{
    background-color: red;
  }
  .is-selecting{
    background-color: blue;
  }
  .cell.is-selected.is-selecting{
    background-color: yellowgreen;
  }
  .contain-locked-cell .is-selecting {
    background-color: #eee;
    cursor: not-allowed;
  }
  .is-locked{
    background-color: purple !important;
    color: #fff;
    cursor: not-allowed;
  }
}
</style>
